package com.es.estatemanagement.config;


import com.es.estatemanagement.service.EstateManagerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.PrintWriter;


/**
 * security配置类
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    EstateManagerService estateManagerService;

    @Resource
    DataSource dataSource;


//    @Resource
//    private MyAccessDenied myAccessDenied;

    @Override
    @ExceptionHandler
    protected void configure(HttpSecurity http) throws Exception {
        //【注意事项】放行资源要放在前面，认证的放在后面
        http
                .csrf().disable()               //关闭csrf网络安全
                .formLogin()                    //开启登录页面,默认登录页面/login
                .loginPage("/login").permitAll()//配置登录页面并对该页面进行授权配置
                .loginProcessingUrl("/dologin") //登录controller请求
                .usernameParameter("username")  //指定登录界面用户名文本框的name值，如果没有指定，默认属性名必须为username
                .passwordParameter("password")  //指定登录界面密码密码框的name值，如果没有指定
                .successForwardUrl("/dologin")  //认证成功 forward 跳转路径,始终在认证成功之后跳转到指定请求
                .and()
                .logout().logoutUrl("/logout").logoutSuccessHandler(new LogoutSuccessHandlerConfig()).clearAuthentication(true).invalidateHttpSession(true)
                .and()
                .authorizeRequests()
                .antMatchers("/images/**", "/js/**", "/css/**", "/fileupload/**", "/ueditor/**", "/lib/**", "/login", "/admin",
                        "/403", "/main", "/", "/favicon.ico", "/cockpit.html", "/estate/fileupload", "/estate/delfile").permitAll()  //放行静态资源
//              .antMatchers("/timeout").permitAll()
                .antMatchers("/swagger-ui.html/**", "/v2/**", "/webjars/springfox-swagger-ui/**", "/webjars/springfox-swagger-ui", "/swagger-resources/**").permitAll()
                .antMatchers("/logout").permitAll()
                .anyRequest().access("@myRBACService.hasPermission(request,authentication)")
//                .antMatchers("/communitylist.html").hasAuthority("ROLE_普通工作人员")
//                .antMatchers("/communitylist.html","/homelist.html").hasAuthority("ROLE_普通管理员")
//                .antMatchers("/communitylist.html","/buildinglst.html").hasAuthority("ROLE_超级管理员")
//                .anyRequest().authenticated()   //任何请求都需要经过验证
//                .and()
//                .sessionManagement()
//                .invalidSessionUrl("/timeout")  //session过期后跳转的URL
                .and()
                .rememberMe()
                .tokenValiditySeconds(20000)
                .rememberMeParameter("remember-me")
                .tokenRepository(persistentTokenRepository())//设置token仓库
                .and()
                .exceptionHandling()                        //出现异常后，方法入口
                .accessDeniedPage("/403")                   //访问被拒绝去的地方（系统默认自定义跳转的方法）
        //.rememberMeCookieName()                     //客户端保存cookie的值
        ;
        http.headers().frameOptions().sameOrigin();
        http.exceptionHandling()
                .authenticationEntryPoint(
                        new AuthenticationEntryPoint() {
                            // 没有登录
                            @Override
                            public void commence(
                                    HttpServletRequest request,
                                    HttpServletResponse response,
                                    AuthenticationException e)
                                    throws IOException, ServletException {
                                response.sendRedirect(request.getContextPath() + "/login");
                            }
                        })
                .accessDeniedHandler(
                        new AccessDeniedHandler() {
                            // 权限不足
                            @Override
                            public void handle(
                                    HttpServletRequest request,
                                    HttpServletResponse response,
                                    AccessDeniedException e)
                                    throws IOException, ServletException {
                                response.sendRedirect(request.getContextPath() + "/403");
                            }
                        });
    }

    //    使用自己的帐号和密码登录，实现基于内存的帐号密码存储，添加自定义用户名和密码后，
    //    后台就不会输出默认的user密码。
    //    在SecurityConfig类中重写configure(AuthenticationManagerBuilder auth)方法
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //基于内存认证授权
//        auth.inMemoryAuthentication()
//                .passwordEncoder(NoOpPasswordEncoder.getInstance())
//                .passwordEncoder(new BCryptPasswordEncoder())
//                .withUser("15900000000").password("$2a$10$y6meJF1eZM.8Sk3pMFuwlOUk426gWqkX..T68HyKTxg97TJgkK/hy").roles("admin")
//                .and()
//                .withUser("user").password("$2a$10$S7Yla1TxTneiZ8vb0dE6E.31L59kicMBnVa6x/J0.eUuCY46rVJb.").roles("user");
        //基于数据库认证授权
        auth.userDetailsService(estateManagerService).passwordEncoder(new BCryptPasswordEncoder());
    }

    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        //设置数据源
        tokenRepository.setDataSource(dataSource);
        //自动创建表,这里就不让程序自动创建表，咱们自己主动创建
        //创建表的sql语句在JdbcTokenRepositoryImpl类中的initDao方法
        //create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)
        //tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

}
